﻿#include "ConfigManager.h"

#include <fast_io/fast_io.h>
#include <fast_io/fast_io_device.h>

#include "../../Utils/Utils.h"
#include "../../Utils/Logger.h"
#include "../../Memory/GameData.h"

#include "../Modules/ModulesManager.h"
#include "../Commands/CommandsManager.h"

fast_io::dir_file ConfigManager::configDirectory{};

bool ConfigManager::loadConfig(std::u8string_view name, fast_io::nt_fs_dirent* nfl) {
	if (name.empty())
		return false;

	if (!nameCheck(name))
		return false;

	if (name != currentConfig)
		saveConfig();  // Save old config
	else
		return true;

	try {
		if (nfl != nullptr)
			SettingObj = nlohmann::json::parse(fast_io::native_file_loader{*nfl});
		else
			SettingObj = nlohmann::json::parse(fast_io::native_file_loader(at(configDirectory), fast_io::u8concat(name, u8".hcfg")));
		currentConfig = name;
		// do sth
		SettingObj["client"] = *reinterpret_cast<const std::string_view*>(&Utils::Utils::ClientName);
		// std::addressof(SettingObj);
		ModuleManager::onLoadConfig(SettingObj);
		if (SettingObj.contains("prefix")) {
			std::string prefix = SettingObj["prefix"];
			CommandMgr::prefix = reinterpret_cast<std::u8string*>(&prefix)->front();
		}
		Logger::LogC(LogGrade::info, u8"Successfully Load Configs!");
		return true;
	} catch (const fast_io::error& e) {
		Logger::LogC(LogGrade::warning, u8"Configs Load Failed! : ", e);
		// createConfig(name);
		return false;
	} catch (std::exception& e) {
		Logger::LogC(LogGrade::warning, u8"Configs Load Failed! : ", fast_io::mnp::os_c_str(reinterpret_cast<const char8_t*>(e.what())));
		return false;
	}

	return true;
}

bool ConfigManager::loadConfigFromClipBoard() {
	auto clipBoardText = Utils::Utils::GetClipboardText();
	if (clipBoardText.empty()) {
		Logger::LogC(LogGrade::warning, u8"Configs Load Failed! : No text in clipboard!");
		return false;
	}
	try {
		SettingObj = nlohmann::json::parse(*reinterpret_cast<std::string*>(&clipBoardText));
		// do sth
		currentConfig.clear();
		SettingObj["client"] = "Helium";
		// std::addressof(SettingObj);
		ModuleManager::onLoadConfig(SettingObj);
		if (SettingObj.contains("prefix")) [[likely]] 
			CommandMgr::prefix = static_cast<char8_t>(SettingObj["prefix"].front());
		Logger::LogC(LogGrade::info, u8"Successfully Load Configs!");
		return true;
	} catch (const fast_io::error& e) {
		Logger::LogC(LogGrade::warning, u8"Configs Load Failed! : ", e);
		// createConfig(name);
		return false;
	} catch (std::exception& e) {
		Logger::LogC(LogGrade::warning, u8"Configs Load Failed! : ", fast_io::mnp::os_c_str(reinterpret_cast<const char8_t*>(e.what())));
		return false;
	}

	return true;
}

bool ConfigManager::createConfig(std::u8string_view name) {
	if (name.empty())
		return false;

	if (!nameCheck(name))
		return false;

	if (name != currentConfig)
		saveConfig();  // Save old config
	else
		return true;

	Logger::LogC(LogGrade::info, u8"Create Config: ", name);
	currentConfig = name;
	saveConfig();

	return true;
}

bool ConfigManager::deleteConfig(std::u8string_view name) {
	if (name.empty())
		return false;
	if (!nameCheck(name))
		return false;
	
	if (DeleteFileW(fast_io::wconcat(fast_io::mnp::code_cvt(Utils::Utils::RoamingStateFold), L"Configs\\", fast_io::mnp::code_cvt(name), L".hcfg").data())) {
		Logger::LogC(LogGrade::info, u8"Successfully Delete Configs!");
		return true;
	} else {
		Logger::LogC(LogGrade::info, u8"Failed to Delete Configs!");
		return false;
	}
}

bool ConfigManager::saveConfig() {
	if (currentConfig.empty())
		return false;
	Logger::LogC(LogGrade::info, u8"Saving Config: ", currentConfig);
	ModuleManager::onSaveConfig(SettingObj);
	std::u8string prefit;
	prefit.push_back(CommandMgr::prefix);
	SettingObj["prefix"] = *reinterpret_cast<std::string*>(&prefit);
	std::string temp = SettingObj.dump(4);
	fast_io::u8obuf_file of(at(configDirectory), fast_io::u8concat(currentConfig, u8".hcfg"), fast_io::open_mode::text);
	println(of, *reinterpret_cast<std::u8string*>(&temp));
	return true;
}

fast_io::vector<std::u8string> ConfigManager::list() {
	fast_io::vector<std::u8string> temp{};
	using std::operator""sv;
	for (auto const& ent : recursive(at(configDirectory))) {
		std::u8string_view view(u8extension(ent));
		if (view == u8".hcfg"sv) {
			std::u8string name_view(std::u8string_view(u8filename(ent)));
			name_view.resize(name_view.find(u8".hcfg"sv));
			temp.emplace_back(std::move(name_view));
		}
	}
	return temp;
}

ConfigManager configMgr{};
